package cn.xeblog.commons.entity.game;

import cn.xeblog.commons.entity.User;
import cn.xeblog.commons.enums.Game;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;
import java.util.*;

/**
 * 游戏房间
 *
 * @author anlingyi
 * @date 2022/5/25 10:30 上午
 */
@Data
public class GameRoom implements Serializable {

    /**
     * 房间号
     */
    private String id;

    /**
     * 游戏
     */
    private Game game;

    /**
     * 几人房
     */
    private int nums;

    /**
     * 游戏模式
     */
    private String gameMode;

    /**
     * 房主
     */
    private User homeowner;

    /**
     * 房间内玩家[用户昵称，玩家]
     */
    private Map<String, Player> users = new LinkedHashMap<>();

    /**
     * 邀请用户列表[用户]
     */
    private transient Set<User> inviteUsers = new HashSet<>();

    /**
     * 玩家
     */
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Player {
        /**
         * 玩家ID
         */
        private String id;
        /**
         * 玩家昵称
         */
        private String username;
        /**
         * 是否已准备，true，已准备
         */
        private boolean readied;

        /**
         * 构建
         *
         * @param id       玩家ID
         * @param username 玩家昵称
         */
        public Player(String id, String username) {
            this.id = id;
            this.username = username;
        }

    }

    /**
     * 添加玩家
     *
     * @param user 指定的玩家
     * @return true, 添加成功，否则,false
     */
    public boolean addUser(User user) {
        synchronized (users) {
            // 当前房间玩家数不能大于房间的容量
            if (getCurrentNums() > nums - 1) {
                return false;
            }

            // 存在的玩家不能再次添加进来
            if (existUser(user)) {
                return false;
            }

            // 添加玩家
            users.put(user.getUsername(), new Player(user.getId(), user.getUsername()));
            return true;
        }
    }

    /**
     * 判断房间中是否存在指定玩家
     *
     * @param user 指定的玩家
     * @return true, 存在，否则,false
     */
    private boolean existUser(User user) {
        return users.get(user.getUsername()) != null;
    }

    /**
     * 移除玩家
     *
     * @param user 指定的玩家
     * @return true, 成功移除，否则，false
     */
    public boolean removeUser(User user) {
        synchronized (users) {
            return users.remove(user.getUsername()) != null;
        }
    }

    /**
     * 当前玩家数量
     *
     * @return 房间内玩家的数量
     */
    public int getCurrentNums() {
        return users.size();
    }

    /**
     * 添加邀请的玩家
     *
     * @param user 指定的玩家
     */
    public void addInviteUser(User user) {
        synchronized (inviteUsers) {
            inviteUsers.add(user);
        }
    }

    /**
     * 移除邀请玩家
     *
     * @param user 指定的玩家
     */
    public void removeInviteUser(User user) {
        synchronized (inviteUsers) {
            inviteUsers.remove(user);
        }
    }

    /**
     * 设置玩家已经准备
     *
     * @param user 指定的玩家
     * @return true，设置成功，否则,false
     */
    public boolean readied(User user) {
        Player player = users.get(user.getUsername());
        if (player == null) {
            return false;
        }

        player.setReadied(true);
        return true;
    }

    /**
     * 判断玩家是否已经取消准备
     *
     * @param user 指定的玩家
     * @return true, 玩家已经取消准备了.否则,false
     */
    public boolean readyCancelled(User user) {
        Player player = users.get(user.getUsername());
        if (player == null) {
            return false;
        }

        player.setReadied(false);
        return true;
    }

    /**
     * 判断指定玩家是否为房主
     *
     * @param username 房主昵称
     * @return true, 房主.否则，false
     */
    public boolean isHomeowner(String username) {
        return homeowner.getUsername().equals(username);
    }

    /**
     * 是否结束
     *
     * @return 当房间容量小于或者等于当前玩家的数量, true, 否则，false
     */
    public boolean isOvered() {
        return nums <= getCurrentNums();
    }

}
